/*
 * Project Name：fileService 
 * Copyright:UMPAY
 * Description：
 */
package com.umfwechat.util;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Ding Zhe
 * @since Apr 10, 2010 2:22:18 PM
 */
public class ZipUtil {
	protected static byte[] buf = new byte[1024];
	private static Logger log = LoggerFactory.getLogger(ZipUtil.class);
	/**
	 * 私有构造函数防止被构建
	 */
	private ZipUtil() {

	}

	/**
	 * 遍历目录并添加文件.
	 * 
	 * @param jos -JAR 输出流
	 * @param file -目录文件名
	 * @param pathName -ZIP中的目录名
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	private static void recurseFiles(final JarOutputStream jos,
			final File file, final String pathName) throws IOException,
			FileNotFoundException {
		//文件夹则往下遍历
		if (file.isDirectory()) {
			final String sPathName = pathName + file.getName() + "/";
			jos.putNextEntry(new JarEntry(sPathName));
			final String[] fileNames = file.list();
			if (fileNames != null) {
				for (int i = 0; i < fileNames.length; i++) {
					recurseFiles(jos, new File(file, fileNames[i]), sPathName);
				}

			}
		}
		//读取文件到ZIP/JAR文件条目
		else {
			//使用指定名称创建新的 ZIP/JAR 条目
			final JarEntry jarEntry = new JarEntry(pathName + file.getName());
			final FileInputStream fin = new FileInputStream(file);
			final BufferedInputStream in = new BufferedInputStream(fin);
			//开始写入新的 ZIP 文件条目并将流定位到条目数据的开始处。
			jos.putNextEntry(jarEntry);

			int len;
			while ((len = in.read(buf)) >= 0) {
				//将字节数组写入当前 ZIP 条目数据
				jos.write(buf, 0, len);
			}

			in.close();
			// 关闭当前 ZIP 条目并定位流以写入下一个条目
			jos.closeEntry();
		}
	}

	/**
	 * 创建 ZIP/JAR 文件.
	 * 
	 * @param directory -要添加的目录
	 * @param zipFile -保存的 ZIP 文件名
	 * @param zipFolderName -ZIP 中的路径名
	 * @param level -压缩级别(0~9)
	 * @throws IOException
	 * @throws FileNotFoundException
	 */
	public static void makeDirectoryToZip(final File directory,
			final File zipFile, final String zipFolderName, final int level)
			throws IOException, FileNotFoundException {

		FileOutputStream fos = null;
		try {
			//输出文件流
			fos = new FileOutputStream(zipFile);
		} catch (final Exception e) {
			//建立打包后的空文件
			new File(zipFile.getParent()).mkdirs();
			zipFile.createNewFile();
			fos = new FileOutputStream(zipFile);
		}

		//使用指定的 Manifest 创建新的 JarOutputStream。清单作为输出流的第一个条目被写入
//		final JarOutputStream jos = new JarOutputStream(fos, new Manifest());
		final JarOutputStream jos = new JarOutputStream(fos);
		jos.setLevel(checkZipLevel(level));
		final String[] fileNames = directory.list();
		if (fileNames != null) {
			for (int i = 0; i < fileNames.length; i++) {
				//对一级目录下的所有文件或文件夹进行处理
				recurseFiles(jos, new File(directory, fileNames[i]),
						zipFolderName == null ? "" : zipFolderName);
			}

		}

		//关闭 ZIP 输出流和正在过滤的流。
		jos.close();

	}

	/**
	 * 检查并设置有效的压缩级别,避免压缩级别设置错的异常
	 * 
	 * @param level -压缩级别
	 * @return 有效的压缩级别或者默认压缩级别
	 */
	public static int checkZipLevel(final int level) {
		if (level < 0 || level > 9) {
			return 7;
		} else {
			return level;
		}

	}

	public static void copyFile(File in, File out) throws Exception {
		FileInputStream fis = null;
		FileOutputStream fos = null;
		try {
			fis = new FileInputStream(in);
			fos = new FileOutputStream(out);
			int i = 0;
			while ((i = fis.read(buf)) != -1) {
				fos.write(buf, 0, i);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			throw e;
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		} finally {
			fis.close();
			fos.close();
		}
	}

	public static void delFile(String filepath) throws IOException {
		try {
			File f = new File(filepath);// 定义文件路径
			if (f.exists() && f.isDirectory()) {// 判断是文件还是目录
				if (f.listFiles().length == 0) {// 若目录下没有文件则直接删除
					f.delete();
				} else {// 若有则把文件放进数组，并判断是否有下级目录
					File[] files = f.listFiles();
					int i = f.listFiles().length;
					for (int j = 0; j < i; j++) {
						if (files[j].isDirectory()) {
							delFile(files[j].getAbsolutePath());// 递归调用del方法并取得子目录路径
						}
						files[j].delete();// 删除文件
					}
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
			throw e;
		} 
		
	}

	public static void zip(File zipFile,List<String> paths) throws IOException{
		Long startTime = System.currentTimeMillis();
		log.info("【ZipUtil.zip】【文件打包开始耗时】= " + (System.currentTimeMillis() - startTime) + " 毫秒");

		log.info("打包开始：待打包文件"+paths.toString());
		zip(zipFile,paths,false);
		log.info("打包结束！");
		log.info("【ZipUtil.zip】【文件打包完成耗时】= " + (System.currentTimeMillis() - startTime) + " 毫秒");

	}
	public static void zip(File zipFile,List<String> paths,Boolean duplicate) throws IOException{
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
		for(String path:paths){
			compressFile(zos,"",path,duplicate);
		}
		zos.flush();
		zos.close();
	}
	public static void zip(File zipFile,String[] paths,Boolean duplicate) throws IOException{
		ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zipFile));
		for(String path:paths){
			compressFile(zos,"",path,duplicate);
		}
		zos.flush();
		zos.close();
	}
	public static void compressFile(ZipOutputStream zos,String rootPath,String directory,Boolean duplicate) throws IOException{
		Long startTime = System.currentTimeMillis();
		File file = new File(directory);
		log.info("正在打包文件："+directory);
		log.info("【ZipUtil.compressFile】【文件正在打包耗时】= " + (System.currentTimeMillis() - startTime) + " 毫秒");

		if(!file.exists()){
			log.info("打包文件不存在："+directory);
			return;
		}
		if(file.isDirectory()){
			String subPath = rootPath+file.getName()+"/";
			ZipEntry entry = new ZipEntry(subPath);
			zos.putNextEntry(entry);
			zos.closeEntry();
			File [] subFiles = file.listFiles(); 
			for(File subFile:subFiles){
				compressFile(zos,subPath,subFile.getPath(),duplicate);
				
			}
			log.info("【ZipUtil.compressFile】【文件正在打包完成耗时】= " + (System.currentTimeMillis() - startTime) + " 毫秒");

		}else{
			ZipEntry entry = new ZipEntry(rootPath+file.getName());
				try {
					zos.putNextEntry(entry);
				} catch (IOException e) {
					if(!duplicate){
						log.info("打包文件失败："+e);
						throw e;
					}
					if(!e.getMessage().startsWith("duplicate")){
						log.info("打包文件失败："+e);
						throw e;
					}
					log.info("打包文件失败："+e);
					return;
				}
			zos.setEncoding("gbk");
			zos.write(getByte(file));
		}
		log.info("打包文件成功："+directory);
		log.info("【ZipUtil.compressFile】【文件打包彻底完成耗时】= " + (System.currentTimeMillis() - startTime) + " 毫秒");

	}
	public static byte[] getByte(File file) throws IOException{
		InputStream is = new FileInputStream(file);
		long length = file.length();
		byte[] bytes = new byte[(int)length];  //加上文件类型4位
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
			offset += numRead;
		}
		if (offset < bytes.length) {
			throw new IOException("Could not completely read file "+file.getName());
		}
		is.close();
		return bytes;
		
	}
	
	public static void main(final String args[]) throws Exception {
		// makeDirectoryToZip();
		// final String homeDir = System.getProperty("user.dir");
		final String homeDir = "E:" + File.separatorChar + "temp"
				+ File.separatorChar + "transAcc";
		String startDateStr = "20100401";
		String endDateStr = "20100410";
		
		String zipFileName = startDateStr + "-" + endDateStr + ".zip";
		final File zipFile = new File(homeDir, File.separatorChar + zipFileName);
		SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
		Date curDate = formatter.parse(startDateStr);
		Date endDate = formatter.parse(endDateStr);
		Calendar cal1 = Calendar.getInstance();
		cal1.setTime(curDate);
		File tempDir = new File(homeDir + File.separatorChar + "temp");
		if (!tempDir.exists()) {
			tempDir.mkdir();
		}

		while (curDate.getTime() <= endDate.getTime()) {
			String fileName = formatter.format(curDate) + ".txt";
			File in = new File(homeDir + File.separatorChar + fileName);
			if (in.exists()) {
				File out = new File(homeDir + File.separatorChar + "temp"
						+ File.separatorChar + fileName);
				copyFile(in, out);
			}
			cal1.add(Calendar.DATE, 1);
			curDate = cal1.getTime();
		}
		final File pagesDirectory = new File(homeDir, "temp");

		System.out.println("Making zip file from folder /src to " + zipFile);

		ZipUtil.makeDirectoryToZip(pagesDirectory, zipFile, "", 9);

		System.out.println("Zip file " + zipFile + " has been made.");

	}
}
